﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Xml;

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

using Sogeti.VSExtention;


namespace Sogeti.QueryWrapper
{

   public delegate void ActionNotifyCallbackDelegate(double value, string currentOperation);

    public class ActionNotifyCallback
    {
        public ActionNotifyCallbackDelegate _delegate;
        public double start;
        public double range;

        public void DoCallback(double value, string operation)
        {
            if(_delegate!=null)
            {
                _delegate(start + value*range, operation);
            }
        }

    }


    public interface IActionNotifyProgress
    {
        void  NOtify(double progress, string currentOperation);
    }

    public class WiqlFolder
    {
        public string Name;
        public string Path;

        public Dictionary<string, string> queries;
        public WiqlFolder()
        {
            queries = new Dictionary<string, string>();
        }

    }

    public class TPQueryWrapper
    {
        protected TfsTeamProjectCollection tpCollection;
        protected WorkItemStore wiStore;
        protected QueryHierarchy qh;
        protected CommonStructureWrapper css;
        protected string tpName;

        public TPQueryWrapper(string tpCollectionUrl, string teamProjectName)
        {
            tpCollection = new TfsTeamProjectCollection(new Uri(tpCollectionUrl));
            wiStore = (WorkItemStore)tpCollection.GetService(typeof(WorkItemStore));
            qh = wiStore.Projects[teamProjectName].QueryHierarchy;
            css = new CommonStructureWrapper(tpCollectionUrl);
            tpName = teamProjectName;

        }
        public TPQueryWrapper(TeamExplorerIntergator teamExplorer)
        {
            if(teamExplorer!=null)
            {
                tpCollection = teamExplorer.tpCollection;
                tpName = teamExplorer.tpName;

                wiStore = (WorkItemStore)tpCollection.GetService(typeof(WorkItemStore));
                qh = wiStore.Projects[tpName].QueryHierarchy;
                css = new CommonStructureWrapper(tpCollection);
            }

        }
        public List<string> GetUsedIterationsInFolder(WiqlFolder fld)
        {
            List<string> lst = new List<string>();

            foreach (KeyValuePair<string, string> q in fld.queries)
            {
                if (q.Value.Contains("System.IterationPath"))
                {
                    string s = ExtractIterationFromWIQLString( q.Value);

                    string path = @"\Iteration\" + s;

                    lst.Add( path);

                    break;
                }
            }
            return lst;
        }

        private string ExtractIterationFromWIQLString(string  sWiql)
        {
            string s="";
            if (sWiql.ToUpper().Contains("WHERE"))
            {
                sWiql = sWiql.Substring(sWiql.ToUpper().IndexOf("WHERE"));
                if (sWiql.Contains("System.IterationPath"))
                {
                    s = sWiql.Substring(sWiql.IndexOf("System.IterationPath"));
                    if (s.ToUpper().Contains(" AND "))
                    {
                        s = s.Substring(0, s.ToUpper().IndexOf(" AND "));
                    }
                    if (s.ToUpper().Contains(")AND "))
                    {
                        s = s.Substring(0, s.ToUpper().IndexOf(")AND"));
                    }
                    if (s.ToUpper().Contains(" OR "))
                    {
                        s = s.Substring(0, s.ToUpper().IndexOf(" OR "));
                    }
                    if (s.ToUpper().Contains(")OR"))
                    {
                        s = s.Substring(0, s.ToUpper().IndexOf(")OR"));
                    }

                    s = s.Substring(s.IndexOf("'" + tpName + @"\") + 1);
                    s = s.Substring(0, s.IndexOf("'"));
                }
            }
            return s;
        }
        private String FindFirstNode(XmlNode startNode)
        {
            if(startNode.HasChildNodes){
                return FindFirstNode(startNode.ChildNodes[0]);
    
            }
            else
            {
                return startNode.Attributes["Path"].Value.ToString();
            }
        }

        public WiqlFolder FindFolderWithFilter(string filter, bool allQueriesFiltered)
        {

            foreach(QueryFolder fld in qh)
            {
                WiqlFolder wiqlFld = FindFolderWithFilter(fld, filter, allQueriesFiltered);
                if (wiqlFld !=null )
                {
                    return wiqlFld;
                }
            }
            return null;
        }


        public WiqlFolder FindFolderWithFilter(QueryFolder fld, string filter, bool allQueriesFiltered)
        {
            bool filterFound = false;
            bool allFiltered = true;

            WiqlFolder wiqlFld = new WiqlFolder{Name=fld.Name, Path=fld.Path};


            foreach (QueryItem itm in fld){
                if (itm.GetType() == typeof(QueryFolder)){
                    return FindFolderWithFilter((QueryFolder)itm, filter, allQueriesFiltered);
                }
                else{
                    string sWIql = ((QueryDefinition)itm).QueryText;
                    wiqlFld.queries.Add(itm.Name, sWIql);

                    if (sWIql.IndexOf(filter)>=0)
                    {
                        filterFound = true;
                    }
                    else{
                           allFiltered=false;
                    }

                }
            }
            
            if( filterFound && allQueriesFiltered && allFiltered){              
                return wiqlFld;
            }
            else{
                return null;
            }

        }


        public WiqlFolder FindWiqlFolder(string path)
        {
           
            QueryFolder fld= FindFolder(path);

             WiqlFolder wiqlFld = new WiqlFolder{Name=fld.Name, Path=fld.Path};


             foreach (QueryItem itm in fld)
             {
                 if (itm.GetType() == typeof(QueryFolder))
                 {
                     //What to do if I ind a folder ?
                     //return FindFolderWithFilter((QueryFolder)itm, filter, allQueriesFiltered);
                 }
                 else
                 {
                     string sWIql = ((QueryDefinition)itm).QueryText;
                     wiqlFld.queries.Add(itm.Name, sWIql);



                 }
             }
             return wiqlFld;
        }
        public QueryFolder FindFolder(string path, QueryFolder fld)
        {
            

            string fldName = path;
            

            if(path.IndexOf(@"/")>0)
            {
                fldName = path.Substring(0, path.IndexOf(@"/"));
            }
           
            
            if (fld.Contains(fldName))
            {
                if(path.IndexOf(@"/")>0){
                        return FindFolder(path.Substring(path.IndexOf(@"/")+1), (QueryFolder)fld[fldName]);
                }else{
                    return (QueryFolder)fld[fldName];
                }
            }
            else
            {
                return null;
            }


       }

        public QueryFolder FindFolder(string path)
        {
            path = path.Replace(qh.Name + @"/", "");
            return FindFolder(path, qh);


        }


        public void SaveQueryFolder(WiqlFolder wiqlFLd)
        {


            qh.Project.Store.RefreshCache(); // Force refresh on Iterations & areas to avoid error in save
            qh.Refresh();

            string path = wiqlFLd.Path.Substring(wiqlFLd.Path.IndexOf(@"/")+1);
            
            QueryFolder fld = FindFolder(path);
            if(fld==null){
                QueryFolder fldParent= FindFolder(path.Substring(0, path.LastIndexOf(@"/")));
 
                fld=new QueryFolder(wiqlFLd.Name);
                fldParent.Add(fld);
            }


            foreach (KeyValuePair<string, string> qry in wiqlFLd.queries)
            {
                QueryDefinition itmTarget = null;
                if(fld.Contains(qry.Key))
                {
                    itmTarget = (QueryDefinition)fld[qry.Key];
                    itmTarget.QueryText = qry.Value;
                }
                else{
                    itmTarget = new QueryDefinition(qry.Key, qry.Value);
                    fld.Add(itmTarget);
                }
            }
            qh.Save();
            qh.Refresh();
            wiStore.RefreshCache();
        }

#region "oldstuf"    
        public void CopyFolder(String sourceFolder, string targetFolder, string search, string replace)
        {

            foreach (QueryFolder fld in qh)
            {
                CopyFolder(fld,sourceFolder, targetFolder, search, replace );
            }
        }

        public void CopyFolder(QueryFolder fldRoot, String sourceFolder, string targetFolder, string search, string replace)
        {

            foreach (QueryItem fld in fldRoot)
            {
                if (fld.GetType() == typeof(QueryFolder))
                {
                    if (fld.Name == sourceFolder)
                    {
                        QueryFolder fldTarget = new QueryFolder(targetFolder);
                        fld.Parent.Add(fldTarget);

                        CopyFolder((QueryFolder)fld, fldTarget,  search, replace);
                        qh.Save();
                    }
                }
            }
        }
        private static void CopyFolder(QueryFolder fld, QueryFolder fldTarget, string search, string replace)
        {
            foreach (QueryItem itm in fld)
            {
                if (itm.GetType() == typeof(QueryFolder))
                {
                    QueryFolder newFolder = new QueryFolder(itm.Name);
                    fldTarget.Add(newFolder);
                    CopyFolder((QueryFolder)itm, newFolder, search, replace);

                }
                else
                {
                    string sWIql = ((QueryDefinition)itm).QueryText;
                    if(search!= String.Empty  && replace!=String.Empty)
                    {
                        sWIql= sWIql.Replace(search, replace);
                    }
                    QueryDefinition itmTarget = new QueryDefinition(itm.Name, sWIql);
                    fldTarget.Add(itmTarget);

                }
            }

        }
#endregion

        public List<WiqlFolder>   ListFolders(string path)
        {
            List<WiqlFolder> lst = new List<WiqlFolder>();

            QueryFolder fld = FindFolder(path);
            if (fld != null) 
            { 
                foreach (QueryItem itm in fld)
                {
                    if (itm.GetType() == typeof(QueryFolder))
                    {
                        lst.Add(new WiqlFolder() { Name = itm.Name, Path = itm.Path });
                        lst.AddRange(ListFolders(itm.Path));
                        //What to do if I ind a folder ?
                        //return FindFolderWithFilter((QueryFolder)itm, filter, allQueriesFiltered);
                    }
                }
            }
            return lst;
        }

        internal List<String> ReplaceIterationinFolder(ref WiqlFolder currentFolder, string oldIteration, string newIteration,   ActionNotifyCallback callback=null)
        {

            List<string> lst = new List<string>();

            oldIteration = ConvertIterationPathToWIQLExpr(oldIteration);
            newIteration = ConvertIterationPathToWIQLExpr(newIteration);

            if(callback==null)
            {
                callback=new ActionNotifyCallback();
            }
                       
            for (int i = 0; i < currentFolder.queries.Count; i++)
            //foreach (KeyValuePair<string, string> q in currentFolder.queries)
            {
                KeyValuePair<string, string> q = currentFolder.queries.ElementAt(i);

                callback.DoCallback(((double)i) / currentFolder.queries.Count, "Searching query " + q.Key + " " + i.ToString() + " of " + currentFolder.queries.Count.ToString());

                if (q.Value.Contains("System.IterationPath"))
                {
                    
                    string sNewQuery = q.Value.Replace(oldIteration, newIteration);
                    if (q.Value != sNewQuery)
                    {
                        callback.DoCallback(((double)i) / currentFolder.queries.Count, "Replaced Iteration path in query " + q.Key);
                        lst.Add(q.Key);
                    }
                    currentFolder.queries[q.Key] = sNewQuery;
                }
            }
            return lst;
        }

        

        private string ConvertIterationPathToWIQLExpr(string oldIteration)
        {
            if (oldIteration.Contains(tpName))
            {
                if (!oldIteration.StartsWith(tpName))
                {
                    oldIteration = oldIteration.Substring(oldIteration.IndexOf(tpName));
                }
                if (oldIteration.Contains(tpName + @"\Iteration\"))
                {
                    oldIteration = oldIteration.Replace(tpName + @"\Iteration\", tpName + @"\");
                }

            }
            else
            {
                throw new Exception("Iteration path in wrong format ");
            }
            return oldIteration;
        }
  
    }
}